package com.handpay.framework.swiper;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;

import com.handpay.framework.utils.CommonUtils;
import com.handpay.zztong.hp.log.HPLog;

/**
 * Created by jmshuai on 2014/8/18.
 * Bbpos的抽象方法，主要写一些bbpos组装apdu的方法。由于他们组装apdu都是一样的。
 */
public abstract class AbstractBbposSwiper implements IPersonalSwiper {
    protected Hashtable<String, String> mHTData = new Hashtable<String, String>();
    protected SwiperMode mSwiperMode;
    protected AsynSwiperLock mLock;
    /**
     * 单密钥加密，固定用的KEY。这个值请不要随意修改！
     */
    protected final static int SINGLE_ENC_DATA_KEY = 0;
    protected final static int SINGLE_ENC_MAC_KEY = 255;

    @Override
    public Hashtable<String, String> batchEncData(Hashtable<Integer, String> htDatas, String factor) {
        return null;
    }

    @Override
    public boolean setMode(SwiperMode flag) {
        mSwiperMode = flag;
        return true;
    }

    @Override
    public Hashtable<String, String> getBankInfo() {
        HPLog.i("DynamiCodeP84","--DynamiCodeP84 of pranent:getBankInfo()--");
        if (!prepareAdditionalData()) {
            return null;
        }
        HPLog.i("DynamiCodeP84","--DynamiCodeP84 of pranent:getBankInfo()1--");
        Hashtable<String, String> result = (Hashtable<String, String>) mHTData
                .clone();
        return result;
    }

    /**
     * 准备一些其他的数据
     */
    protected boolean prepareAdditionalData() {
        HPLog.i("AbstractBbposSwiper", "prepareAdditionalData");
        return true;
    }

    /**
     * 预处理13号密钥需要加密的数据。
     *
     * @param str 需要加密的数据
     * @return
     */
    protected String formatDataAdpu(String str) {
        //两个的实质都是拼apdu指令. 中间的长度，指的是字节长度。
        //所以下面一个分支的计算方法，字符串的长度，要除以2
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            if (mSwiperMode == SwiperMode.SUPER_TRANS) {
                bos.write(str.getBytes());
            } else {
                bos.write(CommonUtils.hexStringToBytes(str));
            }
            while (bos.size() % 8 != 0) {
                bos.write(0x00);
            }
            ByteArrayOutputStream apdu = new ByteArrayOutputStream();
            apdu.write(0x80);
            apdu.write(0xFA);
            apdu.write(0x00);
            apdu.write(0x00);
            apdu.write(bos.size());
            apdu.write(bos.toByteArray());
            byte[] resultByte = apdu.toByteArray();
            bos.close();
            apdu.close();
            return CommonUtils.bytesToHexString(resultByte);
/*            } else {
                if (0 == str.length()%16) {
                    return "80FA0000" + Integer.toHexString(str.length()/2) + str;
                } else {
                    int i = str.length() / 16 + 1;
                    int length = i * 16;
                    StringBuilder sb = new StringBuilder(length);
                    sb.append(str);
                    char[] endZero = new char[length - str.length()];
                    Arrays.fill(endZero, '0');
                    sb.append(endZero);
                    return "80FA0000" + Integer.toHexString(length/2) + sb.toString();
                }
            }*/
        } catch (IOException e1) {
            HPLog.i("AbstractBbposSwiper", "", e1);
        }
        return null;
    }

    protected Hashtable<Integer, String[]> formatMacAdpu(byte[] bos, String time) {
        int type = -1;
        int mMaxSize = 240;
        int count = (int) Math.ceil(bos.length / 1.0d / mMaxSize);
        HPLog.i("AbstractBbposSwiper", "formatMacAdpu:" + count + " + " + mMaxSize);
        Hashtable<Integer, String[]> example = new Hashtable<Integer, String[]>();
        for (int i = 0; i < count; i++) {
            int index = i + 1;
            if (i == 0) {
                if (bos.length <= mMaxSize) {
                    type = 0x05;
                    index = 255;
                } else {
                    type = 0x07;
                }
            } else if (i == count - 1) {
                index = 255;
                type = 0x01;
            } else {
                type = 0x03;
            }

            ByteArrayOutputStream apdu = new ByteArrayOutputStream();
            apdu.write(0x80);
            apdu.write(0xFA);
            apdu.write(type);
            apdu.write(0x00);
            int length = bos.length - i * mMaxSize;
            if (length > mMaxSize) {
                length = mMaxSize;
            }
            apdu.write(length);
            byte c[] = new byte[length];
            System.arraycopy(bos, i * mMaxSize, c, 0, c.length);
            try {
                apdu.write(c);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String mac1 = CommonUtils.bytesToHexString(apdu.toByteArray());
            try {
                apdu.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            HPLog.i("AbstractBbposSwiper", "bos index:" + index + " macStr:" + mac1);
            example.put(index, new String[]{"15", time, mac1});
        }
        return example;
    }

    protected ArrayList<String> formatMacString(byte[] bos) {
        int type = -1;
        int mMaxSize = 160;
        int count = (int) Math.ceil(bos.length / 1.0d / mMaxSize);
        HPLog.i("AbstractBbposSwiper", "formatMacString:" + count + " + " + mMaxSize);
        ArrayList<String> example = new ArrayList<String>();
        for (int i = 0; i < count; i++) {
            int index = i + 1;
            if (i == 0) {
                if (bos.length <= mMaxSize) {
                    type = 0x05;
                    index = 255;
                } else {
                    type = 0x07;
                }
            } else if (i == count - 1) {
                index = 255;
                type = 0x01;
            } else {
                type = 0x03;
            }

            ByteArrayOutputStream apdu = new ByteArrayOutputStream();
            apdu.write(0x80);
            apdu.write(0xFA);
            apdu.write(type);
            apdu.write(0x00);
            int length = bos.length - i * mMaxSize;
            if (length > mMaxSize) {
                length = mMaxSize;
            }
            apdu.write(length);
            byte c[] = new byte[length];
            System.arraycopy(bos, i * mMaxSize, c, 0, c.length);
            try {
                apdu.write(c);
            } catch (IOException e) {
                e.printStackTrace();
            }
            String mac1 = CommonUtils.bytesToHexString(apdu.toByteArray());
            try {
                apdu.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            HPLog.i("AbstractBbposSwiper", "bos index:" + index + " macStr:" + mac1);
            example.add(mac1);
        }
        return example;
    }
}
